home *** CD-ROM | disk | FTP | other *** search
/ Aminet 1 / Aminet - June 1993 [Walnut Creek].iso / usenet / sources / volume90 / util / bsindex1 / part01 next >
Encoding:
Internet Message Format  |  1990-02-02  |  58.6 KB

  1. Path: xanth!cs.odu.edu!Amiga-Request
  2. From: Amiga-Request@cs.odu.edu (Amiga Sources/Binaries Moderator)
  3. Newsgroups: comp.sources.amiga
  4. Subject: v90i041: BBSindex 1.0 - file database utility for BBS-PC!, Part01/03
  5. Message-ID: <11248@xanth.cs.odu.edu>
  6. Date: 2 Feb 90 19:55:18 GMT
  7. Sender: tadguy@cs.odu.edu
  8. Reply-To: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU>
  9. Lines: 2081
  10. Approved: tadguy@cs.odu.edu (Tad Guy)
  11. X-Mail-Submissions-To: Amiga@cs.odu.edu
  12.  
  13. Submitted-by: Eddy Carroll <ECARROLL%vax1.tcd.ie@CUNYVM.CUNY.EDU>
  14. Posting-number: Volume 90, Issue 041
  15. Archive-name: util/bbsindex-1.0/part01
  16.  
  17. BBSindex is a utility for use with the BBS-PC! bulletin board package. It
  18. allows you to list the contents of the file database in a wide variety
  19. of ways. It has its own script language with 20 commands which allows a
  20. wide variety of tasks to be performed.
  21.  
  22. Eddy Carroll                                      ecarroll@vax1.tcd.ie
  23.  
  24. #!/bin/sh
  25. # This is a shell archive.  Remove anything before this line, then unpack
  26. # it by saving it into a file and typing "sh file".  To overwrite existing
  27. # files, type "sh file -c".  You can also feed this as standard input via
  28. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  29. # will see the following message at the end:
  30. #        "End of archive 1 (of 3)."
  31. # Contents:  scripts scripts/bbsindex.scr scripts/filenote.scr
  32. #   scripts/info.scr scripts/move.scr scripts/offline.scr src
  33. #   src/bbs.h src/bbsindex.h src/checkfiles.c src/expression.c
  34. #   src/makefile src/sort.c src/system.h src/tiny.a
  35. # Wrapped by tadguy@xanth on Fri Feb  2 14:54:35 1990
  36. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  37. if test ! -d 'scripts' ; then
  38.     echo shar: Creating directory \"'scripts'\"
  39.     mkdir 'scripts'
  40. fi
  41. if test -f 'scripts/bbsindex.scr' -a "${1}" != "-c" ; then 
  42.   echo shar: Will not clobber existing file \"'scripts/bbsindex.scr'\"
  43. else
  44. echo shar: Extracting \"'scripts/bbsindex.scr'\" \(2360 characters\)
  45. sed "s/^X//" >'scripts/bbsindex.scr' <<'END_OF_FILE'
  46. X#
  47. X# This script builds sorted file catalogues for the Amiga and IBM
  48. X# file areas (i.e. sections 3, 4, 6 and 1), on the Infomatique BBS
  49. X# (Phone: Dublin 302970 (+353-1-302970),  V21/22bis/23)
  50. X#
  51. X# The following constants define the output files for the various filelists
  52. X# Change them to suit.
  53. X
  54. XAmigaFiles    = "Amiga.Files"
  55. XIBMFiles    = "IBM.Files"
  56. X
  57. X#
  58. X# This macro outputs the header for a filelist
  59. X#
  60. Xmacro header # SectionNumber, No. of dirs, SectionName, Filename
  61. X    select Section = $1
  62. X    scan
  63. X    echo "Sorted list of $3 files - %d %w %t"
  64. X    echo ""
  65. X    echo "This file is available in the files section as $4"
  66. X    echo "Files which are not currently available are marked with a *"
  67. X    echo ""
  68. X    echo "Total of %n files in $2 sections, occupying %m Megabytes."
  69. X    echo ""
  70. Xendm
  71. X
  72. X#
  73. X# This macro takes a Section, Directory and title, and produces a list of
  74. X# all the files in that section and directory.
  75. X#
  76. Xmacro sublist # Section, Directory, Title
  77. X    echo "%{$2. $3}\n%u-"
  78. X    select Section = $1 AND Directory = $2
  79. X    list
  80. X    echo ""
  81. Xendm
  82. X
  83. X#
  84. X# Standard file stuff, the same for everything
  85. X#
  86. Xnorequest
  87. Xcheckfiles
  88. Xformat "%15n %w %-6x-%b{B,T}%v{ ,*} %c"
  89. Xsort Section, Directory, Name
  90. X
  91. X#
  92. X# List Amiga files
  93. X#
  94. Xopen $(AmigaFiles)
  95. Xheader 3, 14, "Amiga", "AMIGA.FILES"
  96. Xsublist 3,  1, "General text files"
  97. Xsublist 3,  2, "Technical text files"
  98. Xsublist 3,  3, "Archived text files"
  99. Xsublist 3,  4, "Games"
  100. Xsublist 3,  5, "Screen Hacks"
  101. Xsublist 3,  6, "Graphics, sound & demos"
  102. Xsublist 3,  7, "Graphics & sound programs"
  103. Xsublist 3,  8, "DOS utilities"
  104. Xsublist 3,  9, "Programming utilities"
  105. Xsublist 3, 10, "Resident utilities "
  106. Xsublist 3, 11, "Applications"
  107. Xsublist 3, 12, "Comms programs"
  108. Xsublist 3, 13, "Miscellaneous"
  109. Xsublist 3, 14, "Hardware"
  110. X#
  111. X# List IBM files
  112. X#
  113. Xopen $(IBMfiles)
  114. Xheader 4, 16, "IBM", "IBM.FILES"
  115. Xsublist 4,  1, "General, Miscellaneous"
  116. Xsublist 4,  2, "Miscellaneous Text Files"
  117. Xsublist 4,  3, "Digestives"
  118. Xsublist 4,  4, "DOS File Utilities"
  119. Xsublist 4,  5, "Archive Utilities"
  120. Xsublist 4,  6, "Pop-Up Utilities"
  121. Xsublist 4,  7, "Games & Fun"
  122. Xsublist 4,  8, "Graphics Progs"
  123. Xsublist 4,  9, "Graphics Images & Viewers"
  124. Xsublist 4, 10, "Sound & Music"
  125. Xsublist 4, 11, "Source Code & Programming"
  126. Xsublist 4, 12, "Viruses"
  127. Xsublist 4, 13, "Comms Packages & Utils"
  128. Xsublist 4, 14, "Mainstream Applications"
  129. Xsublist 4, 15, "Education/Tutorials"
  130. Xsublist 4, 16, "Hardware Utils, Performance Tests"
  131. END_OF_FILE
  132. if test 2360 -ne `wc -c <'scripts/bbsindex.scr'`; then
  133.     echo shar: \"'scripts/bbsindex.scr'\" unpacked with wrong size!
  134. fi
  135. # end of 'scripts/bbsindex.scr'
  136. fi
  137. if test -f 'scripts/filenote.scr' -a "${1}" != "-c" ; then 
  138.   echo shar: Will not clobber existing file \"'scripts/filenote.scr'\"
  139. else
  140. echo shar: Extracting \"'scripts/filenote.scr'\" \(511 characters\)
  141. sed "s/^X//" >'scripts/filenote.scr' <<'END_OF_FILE'
  142. X#
  143. X#  This script generates an AmigaDOS batch file to go through all the
  144. X#  files on the system and add a filenote to them, giving the following
  145. X#  information:
  146. X#
  147. X#       (Section, Directory)  BBS Filename    Uploader   File description
  148. X#
  149. X
  150. XOpen "filenote.exec"
  151. X
  152. Xnorequest
  153. Xcheckfiles
  154. X
  155. Xselect Online
  156. X
  157. Xformat 'filenote %f "%6{(%s,%r)} %15n %15o %c"'
  158. Xecho ";"
  159. Xecho "; Batchfile to add comments to all the BBS files in the system
  160. Xecho ";"
  161. Xlist
  162. Xecho ";"
  163. Xecho 'echo "Total of %n files successfully filenoted"'
  164. Xecho ";"
  165. END_OF_FILE
  166. if test 511 -ne `wc -c <'scripts/filenote.scr'`; then
  167.     echo shar: \"'scripts/filenote.scr'\" unpacked with wrong size!
  168. fi
  169. # end of 'scripts/filenote.scr'
  170. fi
  171. if test -f 'scripts/info.scr' -a "${1}" != "-c" ; then 
  172.   echo shar: Will not clobber existing file \"'scripts/info.scr'\"
  173. else
  174. echo shar: Extracting \"'scripts/info.scr'\" \(806 characters\)
  175. sed "s/^X//" >'scripts/info.scr' <<'END_OF_FILE'
  176. X###########################################################################
  177. X#
  178. X# This simple script file merely prints all possible information about
  179. X# each file in the catalogue. It serves as a good demonstration of how
  180. X# to use extended command lines. Practically the whole script is a single
  181. X# extended format command!
  182. X#
  183. X###########################################################################
  184. X
  185. Xnorequest
  186. Xcheckfiles
  187. X
  188. Xformat "\
  189. XFilename      : %n\n\
  190. XUploaded by   : %o\n\
  191. XComment       : %c\n\
  192. XFiletype      : %b{Binary,Text}\n\
  193. XDisk filename : %f\n\
  194. XOrigin        : %l{Local, Remote}\n\
  195. XStatus        : %i{Online, Offline}\n\
  196. XFile state    : %v{Valid, Invalid}\n\
  197. XAccesses      : %a\n\
  198. XSection       : %s\n\
  199. XDirectory     : %r\n\
  200. XUpload date   : %w\n\
  201. XFile size     : %x\n\
  202. X----------"
  203. Xsort name
  204. Xlist
  205. END_OF_FILE
  206. if test 806 -ne `wc -c <'scripts/info.scr'`; then
  207.     echo shar: \"'scripts/info.scr'\" unpacked with wrong size!
  208. fi
  209. # end of 'scripts/info.scr'
  210. fi
  211. if test -f 'scripts/move.scr' -a "${1}" != "-c" ; then 
  212.   echo shar: Will not clobber existing file \"'scripts/move.scr'\"
  213. else
  214. echo shar: Extracting \"'scripts/move.scr'\" \(1001 characters\)
  215. sed "s/^X//" >'scripts/move.scr' <<'END_OF_FILE'
  216. X#
  217. X# Simple script to generate and execute an AmigaDOS batch file to move
  218. X# all the files in a particular section into # a new common directory.
  219. X#
  220. X
  221. X#
  222. X# Set the output file, destination directory and section no's appropriately.
  223. X#
  224. X
  225. XOutFile = "Move.exec"
  226. XDest    = "DH1:Somedirectory"
  227. XSection    = 3
  228. X
  229. X#
  230. X# Use the following MV definition if you have a MV that supports moves
  231. X# across disk boundaries (such as Edwin Hoogerbeets' excellent one).
  232. X#
  233. X
  234. XMV    = "mv %f $(Dest)"
  235. X
  236. X#
  237. X# Use the following MV definition if you want to use plain AmigaDOS
  238. X#
  239. X
  240. X# MV    = "copy %f $(Dest)\ndelete $f"
  241. X
  242. X#
  243. X# Now generate the list of files. We sort by directory name to try
  244. X# and localise disk access
  245. X#
  246. X
  247. Xformat "$(MV)"
  248. XNoRequest
  249. XCheckFiles
  250. XSelect Online and Section = $(Section)
  251. XSort Diskname
  252. Xecho ";"
  253. Xecho "; BBSindex generated AmigaDOS batch file to move files in"
  254. Xecho "; section $(Section) to directory $(Dest)."
  255. Xecho ";"
  256. Xecho "; Created on %d %w %r"
  257. Xecho ";"
  258. Xlist
  259. Xecho ";"
  260. Xecho 'Echo "Total of %n files moved successfully"'
  261. Xecho ";"
  262. END_OF_FILE
  263. if test 1001 -ne `wc -c <'scripts/move.scr'`; then
  264.     echo shar: \"'scripts/move.scr'\" unpacked with wrong size!
  265. fi
  266. # end of 'scripts/move.scr'
  267. fi
  268. if test -f 'scripts/offline.scr' -a "${1}" != "-c" ; then 
  269.   echo shar: Will not clobber existing file \"'scripts/offline.scr'\"
  270. else
  271. echo shar: Extracting \"'scripts/offline.scr'\" \(847 characters\)
  272. sed "s/^X//" >'scripts/offline.scr' <<'END_OF_FILE'
  273. X##############################################
  274. X#
  275. X# This script lists all the files in the
  276. X# BBS catalogue that are offline or invalid
  277. X#
  278. X##############################################
  279. X
  280. Xnorequest
  281. Xcheckfiles
  282. Xsort Section, Name
  283. Xformat "%s:%15n   %-6x-%b{B,T} | %15d\n%28{} | %c"
  284. X
  285. Xecho ""
  286. Xecho "BBS-PC! file report - %d %w %t"
  287. Xecho ""
  288. X
  289. X##############################################
  290. X#
  291. X#             List offline files
  292. X#
  293. X##############################################
  294. X
  295. Xselect Offline
  296. Xecho "%{Files offline}\n%u-"
  297. Xlist
  298. Xecho ""
  299. Xecho "(Total of %n files offline.)"
  300. Xecho ""
  301. X
  302. X##############################################
  303. X#
  304. X#             List invalid files
  305. X#
  306. X##############################################
  307. X
  308. Xselect Online and Invalid
  309. Xecho "%{Files online, but possibly corrupt}\n%u-"
  310. Xlist
  311. Xecho ""
  312. Xecho "(Total of %n files possibly corrupt.)"
  313. Xecho ""
  314. Xecho ""
  315. END_OF_FILE
  316. if test 847 -ne `wc -c <'scripts/offline.scr'`; then
  317.     echo shar: \"'scripts/offline.scr'\" unpacked with wrong size!
  318. fi
  319. # end of 'scripts/offline.scr'
  320. fi
  321. if test ! -d 'src' ; then
  322.     echo shar: Creating directory \"'src'\"
  323.     mkdir 'src'
  324. fi
  325. if test -f 'src/bbs.h' -a "${1}" != "-c" ; then 
  326.   echo shar: Will not clobber existing file \"'src/bbs.h'\"
  327. else
  328. echo shar: Extracting \"'src/bbs.h'\" \(3354 characters\)
  329. sed "s/^X//" >'src/bbs.h' <<'END_OF_FILE'
  330. X/*
  331. X *        Standard BBS-PC! headers (with a few modifications)
  332. X *
  333. X *        Important note: This header file cannot be precompiled with
  334. X *        Lattice C V5.02, because of a bug which prevents bit fields
  335. X *        from working properly when they are precompiled.
  336. X */
  337. X
  338. X/* Official Micro-Systems Software Structures */
  339. X
  340. X#define NUM_TERM    10        /* Number of computer types        */
  341. X#define NUM_SECT    16        /* Number of section names        */
  342. X
  343. X#define CAT_LEN        15        /* File catalogue name lengths    */
  344. X#define DESC_LEN    40        /* File catalogue desc length    */
  345. X#define    FNAME_LEN    12        /* File name lengths            */
  346. X#define FPATH_LEN    30        /* File name path lengths        */
  347. X#define    NAME_LEN    24        /* User name length                */
  348. X#define PASS_LEN    10        /* User password length            */
  349. X#define SECT_LEN    20        /* Section name lengths            */
  350. X#define TERM_LEN    15        /* Computer name lengths        */
  351. X
  352. X/* UDHEAD.DAT record structure */
  353. X
  354. X/* Note some new additions to this structure, for internal tracking */
  355. X
  356. Xtypedef struct {
  357. X    BYTE    type;
  358. X    int        local:1;                    /* True if local upload            */
  359. X    int        bin:1;                        /* True if binary file            */
  360. X    int        valid:1;                    /* True if valid              NEW */
  361. X    int        online:1;                    /* True if file online        NEW    */
  362. X    int        dirnum:5;                    /* Real dir num of file        NEW */
  363. X    int      :7;                            /* Reserved             CHANGED */
  364. X    char    cat_name[CAT_LEN];            /* Catalog filename (key1)        */
  365. X    UWORD    date;                        /* Upload date serial            */
  366. X    BYTE    dir;                        /* Dir number (key2 - seg1)        */
  367. X    BYTE    section;                    /* Section number (key2 - seg2)    */
  368. X    UWORD    accesses;                    /* Number of accesses            */
  369. X    LONG    length;                        /* File length                    */
  370. X    char    disk_name[FNAME_LEN+1];        /* Disk filename                */
  371. X    char    owner[NAME_LEN+1];            /* Owner's name                    */
  372. X    char    desc[DESC_LEN+1];            /* Description text                */
  373. X} UDHEAD;
  374. X
  375. X#define UDSIZE        sizeof(UDHEAD)
  376. X
  377. X
  378. X/* Terminal parameters */
  379. X
  380. Xtypedef struct {
  381. X    int        linefeed: 1;
  382. X    int        :31;
  383. X    BYTE    nuls;
  384. X    BYTE    protocol;
  385. X    BYTE    align;
  386. X    BYTE    page[2];
  387. X    BYTE    cls[4];
  388. X    BYTE    bs[3];
  389. X    char    name[TERM_LEN+1];
  390. X} TRMNL;
  391. X
  392. X
  393. X/* CFGINFO.DAT record structure */
  394. X
  395. Xtypedef struct {
  396. X    int        dir0_ok: 1;        /* Directory 0 downloads            */
  397. X    int        by_call: 1;        /* Time limit per call                */
  398. X    short    max_msg;        /* Maximum messages in system        */
  399. X    short    max_user;        /* Maximum users in system            */
  400. X    short    max_log;        /* Maximum call log                    */
  401. X    short    max_ud;            /* Maximum U/D files                */
  402. X    short    reward;            /* Upload reward                    */
  403. X    short    sleeptime;        /* sleep timeout (adjusted)            */
  404. X    long    dummy;            /* Reserved                            */
  405. X    BYTE    log_p1;            /* Log privilege low                */
  406. X    BYTE    log_p2;            /* Log privilege high                */
  407. X    BYTE    hi_men;            /* Highest menu set                    */
  408. X    BYTE    log_type;        /* Login method                        */
  409. X    short    limit[2];        /* Guest/member time limits         */
  410. X    short    priv[2];        /* Guest/member privileges            */
  411. X    UWORD    rd_acc[2];        /* Guest/member read access            */
  412. X    UWORD    wr_acc[2];        /* Guest/member write access        */
  413. X    UWORD    up_acc[2];        /* Guest/member upload access        */
  414. X    UWORD    dn_acc[2];        /* Guest/member download access        */
  415. X    BYTE    sav_sec[2];        /* Guest/member save section        */
  416. X    BYTE    sec_flg[NUM_SECT];                    /* Section flags            */
  417. X    char    sec_name[NUM_SECT] [SECT_LEN+1];    /* Section names            */
  418. X    char    ud_alt[NUM_SECT] [FPATH_LEN+1];        /* Alternate UD paths        */
  419. X    char    syspass[PASS_LEN+1];                /* Sysop password             */
  420. X    BYTE    menu[2];                            /* Guest/Member menu sets    */
  421. X    BYTE    align;
  422. X    long    dummy2;
  423. X    long    dummy3;
  424. X    TRMNL    trmnl[NUM_TERM];                    /* Terminal parameters        */
  425. X} CFGINFO;
  426. X
  427. X#define CFGSIZE        sizeof(CFGINFO)
  428. END_OF_FILE
  429. if test 3354 -ne `wc -c <'src/bbs.h'`; then
  430.     echo shar: \"'src/bbs.h'\" unpacked with wrong size!
  431. fi
  432. # end of 'src/bbs.h'
  433. fi
  434. if test -f 'src/bbsindex.h' -a "${1}" != "-c" ; then 
  435.   echo shar: Will not clobber existing file \"'src/bbsindex.h'\"
  436. else
  437. echo shar: Extracting \"'src/bbsindex.h'\" \(12473 characters\)
  438. sed "s/^X//" >'src/bbsindex.h' <<'END_OF_FILE'
  439. X/*
  440. X *        BBSINDEX.H
  441. X *    
  442. X *        All the standard variables and other stuff used by all the modules
  443. X *        of BBSindex, and standard BBS-PC! headers (with a few modifications).
  444. X *
  445. X *        Important note: This header file cannot be precompiled with
  446. X *        Lattice C V5.02, because of a bug which prevents bit fields
  447. X *        from working properly when they are precompiled.
  448. X */
  449. X
  450. X#include "bbs.h"
  451. X
  452. X#define TRUE    1
  453. X#define FALSE    0
  454. X
  455. X#define BTOK(x) (((x)+1023)>>10)    /* Convert file size into K */
  456. X
  457. X/*
  458. X *        Default values for command line parameters and script commands
  459. X */
  460. X
  461. X#define FORMAT        "%15n %w %-6x-%b{B,T}  %c\n"
  462. X#define UDNAME        "UDHEAD.DAT"
  463. X#define CFGNAME        "CFGINFO.DAT"
  464. X#define PROGSCRIPT    "BBSCRIPT"
  465. X#define DEFSCRIPT    "BBSindex.scr"
  466. X
  467. X/*
  468. X *    Blocksize determines the largest contiguous memory segment which is
  469. X *    needed. Larger values give faster processing, but need more continuous
  470. X *    memory.
  471. X */
  472. X
  473. X#define    BLOCKSIZE    160                /* Number of records/block (~16K)        */
  474. X#define MAXOUT        1024            /* The maximum length of an output line    */
  475. X#define    MAXCOM        1024            /* Maximum size of a single command        */
  476. X#define MAXSUB        256                /* Maximum size of a sub format string    */
  477. X#define FRAGBLOCK    8192            /* Memory block to allocate in mymalloc */
  478. X#define FRAGTHRESH    200                /* Threshold for mem reqs in mymalloc    */
  479. X#define BUFSIZE        8192            /* Maximum size of output buffer        */
  480. X#define MAXEXPR        100                /* Max number of items in an expression    */
  481. X#define MAXDIRENT    1000            /* Maximum number of unknown dir files    */
  482. X#define DIRFRAG        100                /* Number of dir entries/block alloced    */
  483. X#define DIRNAMESIZE    80                /* Maximum length of directory name        */
  484. X#define MACROLEN    20                /* Maximum length of macro name            */
  485. X#define MAXMACRO    50                /* Maximum number of macros allowed        */
  486. X#define MAXNEST        10                /* Max number of macro nesting levels    */
  487. X#define MAXCONST    20                /* Maximum length of a constant name    */
  488. X
  489. X/* Note: MAXSUB above is allocated on the stack, so don't make it too big */
  490. X
  491. X/*
  492. X *        This structure is used to build a tree structure representing
  493. X *        the expression given with the SELECT command.
  494. X */
  495. Xstruct expr {
  496. X    int        field;            /* Field to test, or boolean operator    */
  497. X    int        op;                /* Operator to test against, if any        */
  498. X    int        num;            /* First data field                        */
  499. X    char    *text;            /* Second data field                    */
  500. X    struct    expr *left;        /* Left subtree                            */
  501. X    struct    expr *right;    /* Right subtree                        */
  502. X};
  503. X
  504. Xtypedef struct expr EXPR;
  505. X
  506. X/*
  507. X *        This structure is used to hold the name of a file found in
  508. X *        a BBS-PC! file directory during CHECKFILES, which does not
  509. X *        exist in the BBS-PC! file catalogue.
  510. X */
  511. Xtypedef struct {
  512. X    char    name[32];        /* Disk filename                        */
  513. X    short    date;            /* In BBS-PC! format, max 16 bits        */
  514. X    short    dirnum;            /* The directory number it was in        */
  515. X    long    size;            /* The size of the file, in bytes        */
  516. X} DIRENTRY;
  517. X
  518. X#define DIRENTRYSIZE    sizeof(DIRENTRY)
  519. X
  520. X/*
  521. X *        This structure holds the names of files to be "ignored" during a
  522. X *        CHECKFILES. I.e. they are marked as valid, even if their filesize
  523. X *        on disk doesn't match that in the file catalogue. This structure
  524. X *        is built up with the IGNORE command.
  525. X */
  526. Xstruct ignore {
  527. X    struct ignore *next;
  528. X    char name[CAT_LEN+1];
  529. X};
  530. X
  531. Xtypedef struct ignore IGNORE;
  532. X
  533. X/*
  534. X *        This structure is used to store macro definitions. Note that
  535. X *        a single block is used to store both the macro and its definition.
  536. X *        The structure is dynamically sized at runtime, to fit whatever
  537. X *        size definition is given. The text[] array (nominally 1) gets
  538. X *        expanded to hold the definition.
  539. X */
  540. Xtypedef struct {
  541. X    char    name[MACROLEN];    /* Name of this macro                    */
  542. X    int        size;            /* Size of macro text                     */
  543. X    char    text[1];        /* Start of macro text                    */
  544. X} MACRO;
  545. X
  546. X#define MACROSIZE        (sizeof(MACRO) - 1)        /* The -1 is for text[1] */
  547. X
  548. X/*
  549. X *        This structure holds a block of parameters for a macro that is
  550. X *        executing.
  551. X */
  552. Xtypedef struct {
  553. X    int        size;            /* Size of parameter block                */
  554. X    char    params[1];        /* Start of parameter block                */
  555. X} PARAM;
  556. X
  557. X#define PARAMSIZE        (sizeof(PARAM) - 1)        /* The -1 is for params[1] */
  558. X
  559. X
  560. X/*
  561. X *        This macro checks to make sure that the file database has been
  562. X *        read in. This is delayed until as late as possible, so that if
  563. X *        the script file contains errors, the errors will be spotted BEFORE
  564. X *        the database is read in. The primary goal here is to save the user
  565. X *        having to wait for 200K or so of database to be read in, just so
  566. X *        they can see they have an error in their script. Instead, the
  567. X *        database is only read in when a command cannot execute without
  568. X *        having access to the files. Such commands are SORT, SCAN, LIST,
  569. X *        CHECKFILES and FOREIGN.
  570. X */
  571. X#define CHECKDATABASE() {if (!readfiles) readdatabase(databasename);}
  572. X
  573. X/*
  574. X *        Global variables, accessible to all modules
  575. X */
  576. X
  577. X#ifdef GLOBAL
  578. X#undef GLOBAL
  579. X#endif
  580. X#ifdef MAIN
  581. X#define GLOBAL
  582. X#else
  583. X#define GLOBAL extern
  584. X#endif
  585. X
  586. XGLOBAL char *script;            /* Array for storing the script                */
  587. XGLOBAL long scriptsize;            /* The size of the current script            */
  588. XGLOBAL long scriptpos;            /* Position in the current script            */
  589. XGLOBAL long linenum;            /* Line number in script file                */
  590. XGLOBAL char out[MAXOUT];        /* Array for storing the output lines        */
  591. XGLOBAL char combuf[MAXCOM];        /* Buffer to hold a single command            */
  592. XGLOBAL char formatstring[MAXCOM];/* Used to store the output format string    */
  593. XGLOBAL char databasename[256];    /* The name of the BBS-PC! file database    */
  594. XGLOBAL char configname[256];    /* The name of the BBS-PC! config file        */
  595. XGLOBAL char scriptname[256];    /* The name of the current script file        */
  596. XGLOBAL UDHEAD **ptrblock;        /* Array of pointers to file records        */
  597. XGLOBAL long numrecs;            /* The number of file headers read in        */
  598. XGLOBAL long compos;                /* Position on the current command line        */
  599. XGLOBAL long comlen;                /* Length of current command line            */
  600. XGLOBAL BPTR outfile;            /* Output file (Default is stdout)            */
  601. XGLOBAL BPTR errorfile;            /* Standard error file (screen usually)        */
  602. XGLOBAL BPTR dirlock;            /* Lock used when scanning directories        */
  603. XGLOBAL struct FileInfoBlock *fib;/* Global fib struct on longword boundary    */
  604. XGLOBAL int checkfiles;            /* TRUE if file directories were scanned    */
  605. XGLOBAL int readfiles;            /* TRUE if database file has been read in    */
  606. XGLOBAL int toscreen;            /* TRUE if output is to screen                */
  607. XGLOBAL int totalbytes;            /* Total number of bytes output so far        */
  608. XGLOBAL int totalfiles;            /* Total number of files output so far        */
  609. XGLOBAL int curbytes;            /* Number of bytes output by last LIST/SCAN    */
  610. XGLOBAL int curfiles;            /* Number of files output by last LIST/SCAN    */
  611. XGLOBAL int sorted;                /* True if file array has been sorted        */
  612. XGLOBAL EXPR tree[MAXEXPR];        /* Array to hold parsed SELECT expression    */
  613. XGLOBAL int numdirentries;        /* Number of fake directory entries            */
  614. XGLOBAL DIRENTRY *direntries[MAXDIRENT];/* Storage for ptrs to dir entries    */
  615. XGLOBAL char dirnames[NUM_SECT][DIRNAMESIZE];/* Storage for directory names    */
  616. XGLOBAL CFGINFO config[1];        /* BBS-PC! Configuration file structure        */
  617. XGLOBAL MACRO *macros[MAXMACRO];    /* Array of ptrs to macro definitions        */
  618. XGLOBAL int nummacros;            /* Number of macros currently defined        */
  619. XGLOBAL PARAM *params[MAXNEST];    /* Array of pointers to macro parameters    */
  620. XGLOBAL int nestlevel;            /* Current macro nest level                    */
  621. XGLOBAL int tracemode;            /* Trace mode; TRUE if tracing enabled        */
  622. XGLOBAL IGNORE *firstignore;        /* Pointer to first filename to ignore        */
  623. X
  624. X/*
  625. X *        Global functions, accessible everywhere
  626. X */
  627. X
  628. Xchar *format();        /* Format output string from file header + format spec    */
  629. Xchar *echoformat();    /* Formats output string for ECHO command                */
  630. Xchar *itoa();        /* Convert integer into ASCII format                    */
  631. Xchar *getstring();    /* Get next string from command buffer                    */
  632. Xvoid *mymalloc();    /* Safe memory tracker that handles out of memory         */
  633. Xvoid *SafeAllocMem();/* Safe AllocMem that handles out of memory            */
  634. Xvoid execscript();    /* Executes all the commands in the current script        */
  635. Xvoid Cleanup();        /* Frees resources and exits program                    */
  636. Xvoid chkabort();    /* Checks for Control-C, and aborts if detected            */
  637. Xvoid putstring();    /* Outputs string to standard I/O                        */
  638. Xvoid flushout();    /* Flushes data buffer to output file                    */
  639. Xvoid parse();        /* Parse command line and build expression tree            */
  640. Xvoid readdatabase();/* Reads in the BBS-PC! UDHEAD.DAT file database        */
  641. Xvoid readconfigfile();/* Reads in the BBS-PC! CFGINFO.DAT file                */
  642. Xvoid print();        /* Prints a string to stderr                            */
  643. Xvoid com_select();    /* SELECT, specifies criteria for files to select        */
  644. Xvoid com_checkfiles();/* Scans file directories, updating catlague entries    */
  645. Xvoid com_sort();    /* Sorts file catalogue into a particular order            */
  646. Xvoid com_foreign();    /* Prints a list of all the unknown foreign files        */
  647. Xvoid com_norequest();/* Stop AmigaDos from putting up requesters            */
  648. Xint match();        /* Returns TRUE if record matches current selection        */
  649. Xint scandir();        /* Scans directory for files, returns TRUE if continue    */
  650. Xint sortcmp();        /* Internal routine used for sorting files                */
  651. X
  652. X/*
  653. X *        print3()
  654. X *        --------
  655. X *        Prints 3 strings to standard error
  656. X */
  657. X#define print2(s1,s2)     (print(s1), print(s2))
  658. X#define print3(s1,s2,s3) (print(s1), print(s2), print(s3))
  659. X
  660. X/*
  661. X *        The list of identifiers used by SORT and SELECT.
  662. X */
  663. X
  664. X#define MAXINDEX 16
  665. X
  666. X#define I_ANY            0
  667. X#define I_ACCESS        1
  668. X#define I_BINARY        2
  669. X#define I_COMMENT        3
  670. X#define I_DISKNAME        4
  671. X#define I_SECTION        5
  672. X#define I_ONLINE        6
  673. X#define I_LOCAL            7
  674. X#define I_NAME            8
  675. X#define I_OWNER            9
  676. X#define I_PATHNAME        10
  677. X#define I_DIRECTORY        11
  678. X#define I_DISKDIRNUM    12
  679. X#define I_VALID            13
  680. X#define I_DATE            14
  681. X#define I_SIZE            15
  682. X#define I_KSIZE            16
  683. X
  684. XGLOBAL struct {
  685. X    int tag;
  686. X    char *name;
  687. X} indexes[MAXINDEX]
  688. X#ifdef MAIN
  689. X= {
  690. X
  691. X{    I_ACCESS,        "ACCESS"},        /* Number of times file was accessed    */
  692. X{    I_BINARY,        "BINARY"},        /* True if Binary, False if text        */
  693. X{    I_COMMENT,        "COMMENT"},        /* The file comment                        */
  694. X{    I_DISKNAME,        "DISKNAME"},    /* The name of the file on disk            */
  695. X{    I_SECTION,        "SECTION"},        /* # of the section the file is in        */
  696. X{    I_ONLINE,        "ONLINE"},        /* True if file online                    */
  697. X{    I_LOCAL,        "LOCAL"},        /* True if file uploaded locally        */
  698. X{    I_NAME,            "NAME"},        /* The name of the file in the catalog    */
  699. X{    I_OWNER,        "OWNER"},        /* The name of uploader of the file        */
  700. X{    I_PATHNAME,        "PATHNAME"},    /* Pathname to file on disk                */
  701. X{    I_DIRECTORY,    "DIRECTORY"},    /* # of directory file is in            */
  702. X{    I_DISKDIRNUM,    "DISKDIRNUM"},    /* # of disk directory file is in        */
  703. X{    I_VALID,        "VALID"},        /* True if file is Valid                */
  704. X{    I_DATE,            "DATE"},        /* The date the file was uploaded        */
  705. X{    I_SIZE,            "SIZE"},        /* The size of the file                    */
  706. X{    I_KSIZE,        "KSIZE"}        /* The size of the file in K            */
  707. X}
  708. X#endif
  709. X;
  710. X
  711. XGLOBAL char *months[]
  712. X#ifdef MAIN
  713. X= {
  714. X    "xxx",
  715. X    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
  716. X    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
  717. X}
  718. X#endif
  719. X;
  720. X
  721. X/*
  722. X *        Special characters that can occur in the script
  723. X */
  724. X#define CHAR_TAB        '\t'
  725. X#define CHAR_SPACE        ' '
  726. X#define CHAR_HASH        '#'
  727. X#define CHAR_NL            '\n'
  728. X#define CHAR_ESC        '\\'
  729. X#define CHAR_QUOTE        '\''
  730. X#define CHAR_QUOTES        '\"'
  731. X#define CHAR_SEMI        ';'
  732. X#define CHAR_COMMA        ','
  733. X#define CHAR_EQUALS        '='
  734. X#define CHAR_DOLLAR        '$'
  735. X#define CHAR_NULL        '\0'
  736. X
  737. X#define CHAR_ASCEND        '+'
  738. X#define CHAR_DESCEND    '-'
  739. X
  740. X/*
  741. X *        The following symbols are used in the expression tree
  742. X */
  743. X
  744. X/*
  745. X *        Boolean operations, which share storage with field selectors
  746. X */
  747. X
  748. X#define E_AND        30    /* <left> AND <right>    */
  749. X#define    E_OR        31    /* <left> OR <right>    */
  750. X#define    E_NOT        32    /* NOT <left>            */
  751. X#define E_ALL        33    /* Always true            */
  752. X
  753. X/*
  754. X *        Comparison operators, used for comparing record elements
  755. X */
  756. X#define    E_EQ        34    /* Record == Value        */
  757. X#define E_NE        35    /* Record != Value        */
  758. X#define E_LT        36    /* Record <  Value        */
  759. X#define E_GT        37    /* Record >  Value        */
  760. X#define E_LE        38    /* Record <= Value        */
  761. X#define E_GE        39    /* Record >= Value        */
  762. X
  763. X#define E_OPENPAR    40    /* Open parameter token        */
  764. X#define E_CLOSEPAR    41    /* Close parameter token    */
  765. X
  766. X#define E_NUMBER    42    /* Any numeric value        */
  767. X#define E_STRING    43    /* Anything in quotes        */
  768. X#define E_END        44    /* End of command line        */
  769. X
  770. X#define E_TEXT        45    /* File is a text file        */
  771. X#define E_REMOTE    46    /* File is a remote file    */
  772. X#define E_INVALID    47    /* File is invalid            */
  773. X#define E_OFFLINE    48    /* File is offline            */
  774. X
  775. X
  776. X/*
  777. X *        Wildcard special fields for strings
  778. X */
  779. X#define tokentowild(x) ((x)+50)
  780. X
  781. X#define W_OWNER        tokentowild(I_OWNER)
  782. X#define W_NAME        tokentowild(I_NAME)
  783. X#define W_DISKNAME    tokentowild(I_DISKNAME)
  784. X#define W_COMMENT    tokentowild(I_COMMENT)
  785. END_OF_FILE
  786. if test 12473 -ne `wc -c <'src/bbsindex.h'`; then
  787.     echo shar: \"'src/bbsindex.h'\" unpacked with wrong size!
  788. fi
  789. # end of 'src/bbsindex.h'
  790. fi
  791. if test -f 'src/checkfiles.c' -a "${1}" != "-c" ; then 
  792.   echo shar: Will not clobber existing file \"'src/checkfiles.c'\"
  793. else
  794. echo shar: Extracting \"'src/checkfiles.c'\" \(6592 characters\)
  795. sed "s/^X//" >'src/checkfiles.c' <<'END_OF_FILE'
  796. X/*
  797. X * CHECKFILES.C
  798. X *
  799. X * This module contains routines to read in the disk directory, search
  800. X * the file database for each filename found to see if it matches, etc.
  801. X *
  802. X */
  803. X
  804. X#ifndef LATTICE_50
  805. X#include "system.h"
  806. X#endif
  807. X#include "bbsindex.h"
  808. X
  809. X/*
  810. X *        addunknown()
  811. X *        ------------
  812. X *        Adds a new entry to the list of unknown files found. If necessary,
  813. X *        more memory will be allocated to hold the new entry.
  814. X */
  815. Xint addunknown(name, size, date, dirnum)
  816. Xchar *name;
  817. Xlong size;
  818. Xint date, dirnum;
  819. X{
  820. X    static DIRENTRY *dirbase, *dir;
  821. X
  822. X    if (numdirentries >= MAXDIRENT) {
  823. X        scripterror("directory table full. Skipping rest of files\n");
  824. X        return (FALSE);
  825. X    }
  826. X    if ((numdirentries % DIRFRAG) == 0)     /* Allocate new block */
  827. X        dirbase = mymalloc(DIRENTRYSIZE * DIRFRAG);
  828. X
  829. X    dir = &dirbase[numdirentries % DIRFRAG];
  830. X
  831. X    strcpy(dir->name, name);
  832. X    dir->size    = size;
  833. X    dir->date    = date;
  834. X    dir->dirnum    = dirnum;
  835. X
  836. X    direntries[numdirentries++] = dir;
  837. X    return (TRUE);
  838. X}
  839. X
  840. X/*
  841. X *        find()
  842. X *        ------
  843. X *        Does a binary search of the file records looking for the specified
  844. X *        filename. Returns pointer to the file record if found, NULL if not
  845. X *        found.
  846. X */
  847. XUDHEAD *find(name)
  848. Xchar *name;
  849. X{
  850. X    long low = 0, high = numrecs -1;
  851. X    long mid;
  852. X    int cmp;
  853. X
  854. X    while (high >= low) {
  855. X        mid = (low + high) / 2;
  856. X        cmp = stricmp(ptrblock[mid]->disk_name, name);
  857. X        if (!cmp && ptrblock[mid]->type == 0)        /* Found match */
  858. X            return (ptrblock[mid]);
  859. X        if (cmp > 0)                        /* Too far ahead, go backwards */
  860. X            high = mid-1;
  861. X        else                                /* Too far below, go forwards */
  862. X            low  = mid+1;
  863. X    }
  864. X    return (NULL);
  865. X}
  866. X
  867. X/*
  868. X *        scandir()
  869. X *        ---------
  870. X *        Scans directory, adding the files found either to the 'unknown'
  871. X *        list or updating the pointers in the main file database appropriately.
  872. X */
  873. Xint scandir(dirname, dirnum)
  874. Xchar *dirname;
  875. Xint dirnum;
  876. X{
  877. X    UDHEAD *f;
  878. X    struct tm *filedate;
  879. X    int bbspcdate;
  880. X
  881. X    dirlock = Lock(dirname, ACCESS_READ);
  882. X    if (dirlock == NULL) {
  883. X        scripterror("can't find directory ");
  884. X        print2(dirname, ", skipping\n");
  885. X        return (TRUE);
  886. X    }
  887. X
  888. X    if (!Examine(dirlock, fib)) {
  889. X        scripterror("can't examine directory ");
  890. X        print2(dirname, ", skipping\n");
  891. X        UnLock(dirlock);
  892. X        dirlock = NULL;
  893. X        return (TRUE);
  894. X    }
  895. X
  896. X    while (ExNext(dirlock, fib)) {
  897. X        chkabort();
  898. X        if (fib->fib_DirEntryType > 0)    /* Skip over directories */
  899. X            continue;
  900. X        if (f = find(fib->fib_FileName)) {
  901. X            f->online = 1;
  902. X            f->valid = (fib->fib_Size == f->length);
  903. X            f->dirnum = dirnum;
  904. X        } else {
  905. X            /*
  906. X             *        Convert AmigaDOS date (# days since 1/1/78, # mins
  907. X             *        since midnight) into ANSI date (# seconds since 1/1/70)
  908. X             *        then convert that into BBS-PC! format.
  909. X             */
  910. X            long ansidate;
  911. X            ansidate = (fib->fib_Date.ds_Days + (365 * 8) + 2) * 86400;
  912. X            filedate = gmtime(&ansidate);
  913. X            bbspcdate = (((filedate->tm_year * 13) +
  914. X                          (filedate->tm_mon+1)) * 32) +
  915. X                           filedate->tm_mday;
  916. X            if (!addunknown(fib->fib_FileName, fib->fib_Size, bbspcdate,
  917. X                                                                    dirnum)) {
  918. X                UnLock(dirlock);
  919. X                dirlock = NULL;
  920. X                return (FALSE);
  921. X            }
  922. X
  923. X        }
  924. X    }
  925. X    if (IoErr() != ERROR_NO_MORE_ENTRIES) {
  926. X        scripterror("error reading directory ");
  927. X        print2(dirname, ", skipping\n");
  928. X    }
  929. X    UnLock(dirlock);
  930. X    dirlock = NULL;
  931. X    return (TRUE);
  932. X}
  933. X
  934. X/*
  935. X *        diskcmp()
  936. X *        ---------
  937. X *        Compares the disk filenames of two file headers, and returns true
  938. X *        if they are equal. Used by the sort routine in check_files().
  939. X */
  940. Xint diskcmp(f1,f2)
  941. XUDHEAD **f1, **f2;
  942. X{
  943. X    return (stricmp((*f1)->disk_name, (*f2)->disk_name));
  944. X}
  945. X
  946. X/*
  947. X *        com_checkfiles()
  948. X *        ----------------
  949. X *        This command scans the file directories specified on the command
  950. X *        line (or if none, then using those specified in the CFGINFO.DAT
  951. X *        file). Each file in the catalogue is searched for in the file
  952. X *        catalogue, and those that are found are marked as "Online"; if
  953. X *        the disk filesize matches the catalogue filesize, then their
  954. X *        "valid" flag is also set. Files which are not found are stored
  955. X *        in a seperate array, which can be printed with the FOREIGN command.
  956. X *        After this, any other files listed in the IGNORE list are also marked
  957. X *        as valid.
  958. X *
  959. X *        Note that before the scan, the files are sorted into alphabetical
  960. X *        order, by diskname, to allow a binary search to be done. Afterwards,
  961. X *        if this disrupted a previous sorting order, they are sorted back
  962. X *        to their original state.
  963. X */
  964. Xvoid com_checkfiles()
  965. X{
  966. X    int dirnum;
  967. X    IGNORE *ig;
  968. X    UDHEAD *f;
  969. X
  970. X    if (checkfiles)
  971. X        return;
  972. X
  973. X    CHECKDATABASE();
  974. X    qsort(ptrblock, numrecs, sizeof(UDHEAD *), diskcmp);
  975. X    if (compos >= comlen) {
  976. X        readconfigfile();
  977. X        for (dirnum = 0; dirnum < NUM_SECT && dirnames[dirnum][0]; dirnum++) {
  978. X            chkabort();
  979. X            if (!scandir(dirnames[dirnum], dirnum))
  980. X                break;
  981. X        }
  982. X    } else {
  983. X        for (dirnum = 0; dirnum < NUM_SECT; dirnum++) {
  984. X            if (compos >= comlen)
  985. X                break;
  986. X            strcpy(dirnames[dirnum], getstring());
  987. X            chkabort();
  988. X            if (!scandir(dirnames[dirnum], dirnum))
  989. X                break;
  990. X        }
  991. X    }
  992. X    /*
  993. X     *        Now mark any "ignored" files as valid.
  994. X     */
  995. X    for (ig = firstignore; ig; ig = ig->next) {
  996. X        if (f = find(ig->name))
  997. X            f->valid = 1;
  998. X    }
  999. X    chkabort();
  1000. X    if (sorted)
  1001. X        qsort(ptrblock, numrecs, sizeof(UDHEAD *), sortcmp);
  1002. X    checkfiles = TRUE;
  1003. X}
  1004. X
  1005. X/*
  1006. X *        com_foreign()
  1007. X *        -------------
  1008. X *        This command prints out the list of foreign files, i.e. files
  1009. X *        not in the catalogue, using the format string setup with
  1010. X *        FORMAT. Not all fields are valid.
  1011. X */
  1012. Xvoid com_foreign()
  1013. X{
  1014. X    /*
  1015. X     *        Standard file header template for foreign files.
  1016. X     *        Note file[] is an array, so we can say file->x instead of file.x
  1017. X     */
  1018. X    static UDHEAD file[1] = {{
  1019. X        0,                        /* Record type (== valid)                */
  1020. X        1, 1, 1, 1,             /* Local, Binary, Valid and Online :-)    */
  1021. X        0,                        /* Directory number is set later        */
  1022. X        "",                        /* Catalogue filename, filled in later    */
  1023. X        0,                        /* Date is set later                    */
  1024. X        0, 0, 0,                /* Section 0, Directory 0, no accesses    */
  1025. X        0,                        /* Length is set later                    */
  1026. X        "",                        /* Disk name is set later                */
  1027. X        "AmigaDos",                /* The file owner                        */
  1028. X        "Directory = ",            /* File comment, set later                */
  1029. X    }};
  1030. X
  1031. X    int i;
  1032. X
  1033. X    if (!checkfiles) {
  1034. X        scripterror("can't do FOREIGN before CHECKFILES\n");
  1035. X        Cleanup(10);
  1036. X    }
  1037. X
  1038. X    for (i = 0; i < numdirentries; i++) {
  1039. X        chkabort();
  1040. X        /* Setup actual file parameters for format() */
  1041. X        strcpy(file->disk_name, direntries[i]->name);
  1042. X        strncpy(file->cat_name, direntries[i]->name, CAT_LEN);
  1043. X        strncpy(file->desc+12, dirnames[direntries[i]->dirnum], DESC_LEN-12);
  1044. X        file->desc[DESC_LEN] = CHAR_NULL;
  1045. X        file->length    = direntries[i]->size;
  1046. X        file->date        = direntries[i]->date;
  1047. X        file->dirnum    = direntries[i]->dirnum;
  1048. X        format(out, MAXOUT, formatstring, file, checkfiles);
  1049. X        putstring(out);
  1050. X    }
  1051. X}
  1052. END_OF_FILE
  1053. if test 6592 -ne `wc -c <'src/checkfiles.c'`; then
  1054.     echo shar: \"'src/checkfiles.c'\" unpacked with wrong size!
  1055. fi
  1056. # end of 'src/checkfiles.c'
  1057. fi
  1058. if test -f 'src/expression.c' -a "${1}" != "-c" ; then 
  1059.   echo shar: Will not clobber existing file \"'src/expression.c'\"
  1060. else
  1061. echo shar: Extracting \"'src/expression.c'\" \(11470 characters\)
  1062. sed "s/^X//" >'src/expression.c' <<'END_OF_FILE'
  1063. X/*
  1064. X * EXPRESSION.C
  1065. X *
  1066. X * This module contains the routines needed to parse and evaluate an
  1067. X * expression. This is used while selecting which files to print.
  1068. X *
  1069. X *    This is the BNF for the set of expressions recognised by the
  1070. X *    database searcher. It doesn't contain any semantic information however.
  1071. X *
  1072. X *    Expression            ::= Boolean | Boolean Operator Expression | ALL
  1073. X *    Operator            ::= AND | OR 
  1074. X *    Boolean                ::= NOT Boolean                |
  1075. X *                            '(' Expression ')'        |
  1076. X *                            BoolIdent                |
  1077. X *                            NumIdent    Op Value    |
  1078. X *                            StringIdent Op String    |
  1079. X *                            DateIdent    Op Date
  1080. X *    Op                    ::= '<' | '>' | '<=' | '>=' | '=' | '<>'
  1081. X *    BoolIdent            ::= BINARY | ONLINE | LOCAL | VALID
  1082. X *    StringIdent            ::= COMMENT | DISKNAME | NAME | OWNER | PATHNAME
  1083. X *    NumIdent            ::= ACCESS | SECTION | DIRECTORY | DISKDIRNUM |
  1084. X *                            SIZE | KSIZE
  1085. X *    DateIdent            ::= DATE
  1086. X *    String                ::= (Text enclosed in quotes)
  1087. X *    Value                ::= (A number)
  1088. X *    Date                ::= (A date in the format "dd-mon-yy")
  1089. X *
  1090. X */
  1091. X
  1092. X#ifndef LATTICE_50
  1093. X#include "system.h"
  1094. X#endif
  1095. X
  1096. X#include "bbsindex.h"
  1097. X
  1098. X#define mystrcmp stricmp        /* Make match() insensitive to case */
  1099. X
  1100. X/*
  1101. X *        BNF procedures
  1102. X */
  1103. X
  1104. Xvoid bnf_op(), bnf_date(), bnf_expression(), bnf_boolean();
  1105. X
  1106. X/*
  1107. X *        Global variable(s)
  1108. X */
  1109. X
  1110. Xstatic int treepos;                /* Next free entry in tree array    */
  1111. Xstatic int curtoken;            /* Current token                    */
  1112. Xstatic int curvalue;            /* Current number with E_NUMBER        */
  1113. Xstatic char curstring[MAXCOM];    /* Current string with E_STRING        */
  1114. X
  1115. X/*
  1116. X *        Tokens recognised as special in expressions
  1117. X */
  1118. X
  1119. Xstruct {
  1120. X    int tag;
  1121. X    char *name;
  1122. X} tokens[] = {
  1123. X    
  1124. X    {    E_EQ,            "="            },
  1125. X    {    E_NE,            "<>"        },
  1126. X    {    E_LE,            "<="        },
  1127. X    {    E_GE,            ">="        },
  1128. X    {    E_LT,            "<"            },
  1129. X    {    E_GT,            ">"            },
  1130. X    {    E_AND,            "AND"        },
  1131. X    {    E_OR,            "OR"        },
  1132. X    {    E_NOT,            "NOT"        },
  1133. X    {    E_ALL,            "ALL"        },
  1134. X    {    E_OPENPAR,        "("            },
  1135. X    {    E_CLOSEPAR,        ")"            },
  1136. X    {    E_TEXT,            "TEXT"        },
  1137. X    {    E_REMOTE,        "REMOTE"    },
  1138. X    {    E_INVALID,        "INVALID"    },
  1139. X    {    E_OFFLINE,        "OFFLINE"    },
  1140. X    {    NULL,            NULL        }
  1141. X};
  1142. X
  1143. X/*
  1144. X *        wild()
  1145. X *        ------
  1146. X *        This routine does a wildcard match on the two specified strings.
  1147. X *        The first string contains the string to check, and the second string
  1148. X *        containts the wildcard pattern to check against. The special wild
  1149. X *        card characters are '?' which matches any single characters, and
  1150. X *        '*' which matches any number of characters. 0 is returned if the
  1151. X *        the two strings match, else a +ve or -ve number.
  1152. X *
  1153. X */
  1154. Xint wild(s,w)
  1155. Xchar *s;
  1156. Xchar *w;
  1157. X{
  1158. X    char *p;
  1159. X    char ch;
  1160. X
  1161. X    while (*w && *s) {
  1162. X        switch (*w) {
  1163. X
  1164. X            case '*':
  1165. X                ch = toupper(w[1]);
  1166. X                if (!ch)
  1167. X                    return (0);
  1168. X                for (p = s; *p; p++) {
  1169. X                    if (toupper(*p) == ch || ch == '?') {
  1170. X                        if (!wild(p,w+1))
  1171. X                            return (0);
  1172. X                    }
  1173. X                }
  1174. X                return (toupper(*p)-ch);
  1175. X
  1176. X            case '?':
  1177. X                break;
  1178. X
  1179. X            default:
  1180. X                if (toupper(*s) != toupper(*w))
  1181. X                    return (toupper(*s)-toupper(*w));
  1182. X        }
  1183. X        w++;
  1184. X        s++;
  1185. X    }
  1186. X    return (toupper(*s)-toupper(*w));
  1187. X}
  1188. X
  1189. X
  1190. X/*
  1191. X *        Dirty great macro to compare two values according to an operator
  1192. X */
  1193. X#define e_cmp(v1,op,v2)                        \
  1194. X    switch (op) {                            \
  1195. X        case E_EQ: return ((v1) == (v2));    \
  1196. X        case E_NE: return ((v1) != (v2));    \
  1197. X        case E_LT: return ((v1) <  (v2));    \
  1198. X        case E_GT: return ((v1) >  (v2));    \
  1199. X        case E_LE: return ((v1) <= (v2));    \
  1200. X        case E_GE: return ((v1) >= (v2));    \
  1201. X    }
  1202. X
  1203. X#define e_numcmp(n)        e_cmp(n, e->op, e->num)
  1204. X#define e_strcmp(s)        e_cmp(mystrcmp(s,e->text), e->op, 0)
  1205. X#define e_wildcmp(s)    e_cmp(wild(s,e->text), e->op, 0)
  1206. X
  1207. X/*
  1208. X *        match()
  1209. X *        -------
  1210. X *        Scans the the parse tree, and returns TRUE if the current
  1211. X *        record matches the criteria in the tree, else FALSE.
  1212. X *
  1213. X *        Aside: Aren't C macros wonderful? Just think how long this function
  1214. X *        would be if it wasn't for the above e_cmp, e_numcmp and e_strcmp
  1215. X *        macros.
  1216. X */
  1217. Xint match(p, e)
  1218. XUDHEAD *p;
  1219. XEXPR *e;
  1220. X{
  1221. X    switch (e->field) {
  1222. X        
  1223. X        case E_AND:            return (match(p, e->left) && match(p, e->right));
  1224. X        case E_OR:            return (match(p, e->left) || match(p, e->right));
  1225. X        case E_NOT:            return (!match(p, e->left));
  1226. X        case E_ALL:            return (TRUE);
  1227. X        case I_LOCAL:        return ((int)p->local);
  1228. X        case I_BINARY:        return ((int)p->bin);
  1229. X        case I_VALID:        return ((int)p->valid);
  1230. X        case I_ONLINE:        return ((int)p->online);
  1231. X        case E_REMOTE:        return (!(int)p->local);
  1232. X        case E_TEXT:        return (!(int)p->bin);
  1233. X        case E_INVALID:        return (!(int)p->valid);
  1234. X        case E_OFFLINE:        return (!(int)p->online);
  1235. X        case I_ACCESS:        e_numcmp(p->accesses);
  1236. X        case I_DATE:        e_numcmp(p->date);
  1237. X        case I_DIRECTORY:    e_numcmp(p->dir);
  1238. X        case I_DISKDIRNUM:    e_numcmp(p->dirnum);
  1239. X        case I_KSIZE:        e_numcmp(BTOK(p->length));
  1240. X        case I_SECTION:        e_numcmp(p->section);
  1241. X        case I_SIZE:        e_numcmp(p->length);
  1242. X        case I_DISKNAME:    e_strcmp(p->disk_name);
  1243. X        case I_COMMENT:        e_strcmp(p->desc);
  1244. X        case I_NAME:        e_strcmp(p->cat_name);
  1245. X        case I_OWNER:        e_strcmp(p->owner);
  1246. X        case W_DISKNAME:    e_wildcmp(p->disk_name);
  1247. X        case W_COMMENT:        e_wildcmp(p->desc);
  1248. X        case W_NAME:        e_wildcmp(p->cat_name);
  1249. X        case W_OWNER:        e_wildcmp(p->owner);
  1250. X    }
  1251. X}
  1252. X
  1253. X/*
  1254. X *        newnode()
  1255. X *        ---------
  1256. X *        This function allocates a new node from the tree array, and returns
  1257. X *        a pointer to it. If overflow occurs, it aborts with an error message.
  1258. X */
  1259. X
  1260. XEXPR *newnode()
  1261. X{
  1262. X    treepos++;
  1263. X    if (treepos >= MAXEXPR) {
  1264. X        scripterror("expression to complex\n");
  1265. X        Cleanup(10);
  1266. X    }
  1267. X    return (&tree[treepos]);
  1268. X}
  1269. X
  1270. X/*
  1271. X *        readtoken()
  1272. X *        -----------
  1273. X *        This function reads the next token from the command line, starting
  1274. X *        at position curpos. curtoken is set to the type of token received.
  1275. X *        If it was E_STRING, then curstring points to the string it
  1276. X *        represents (without the quotes). If it was E_NUM, then curvalue
  1277. X *        points to the number represented. If the end of the line is
  1278. X *        reached, E_END is automatically set.
  1279. X */
  1280. X
  1281. X#define nextch()        (ch = combuf[compos++])
  1282. X#define ungetnext()        (compos--)
  1283. X
  1284. Xvoid readtoken()
  1285. X{
  1286. X    char *p = curstring, ch;
  1287. X    int i;
  1288. X
  1289. X    if (compos >= comlen) {
  1290. X        curtoken = E_END;
  1291. X        return;
  1292. X    }
  1293. X
  1294. X    do {
  1295. X        nextch();
  1296. X    } while (ch == CHAR_SPACE);
  1297. X
  1298. X    if (ch == CHAR_QUOTES) {            /* Handle string in quotes */
  1299. X        curtoken = E_STRING;
  1300. X        nextch();
  1301. X        if (*p == CHAR_NULL) {
  1302. X            curtoken = E_END;
  1303. X            return;
  1304. X        }
  1305. X        do {
  1306. X            *p++ = ch;
  1307. X            nextch();
  1308. X        } while (ch && ch != CHAR_QUOTES);
  1309. X        *p = CHAR_NULL;
  1310. X        return;
  1311. X    }
  1312. X
  1313. X    if (isdigit(ch)) {                /* Numeric value? */
  1314. X        curtoken = E_NUMBER;
  1315. X        curvalue = 0;
  1316. X        do {
  1317. X            curvalue = curvalue * 10 + (ch - '0');
  1318. X            nextch();
  1319. X        } while (isdigit(ch));
  1320. X        ungetnext();
  1321. X        return;
  1322. X    }
  1323. X
  1324. X    if (isalpha(ch)) {                /* Alphabetic identifier? */
  1325. X        do {
  1326. X            *p++ = ch;
  1327. X            nextch();
  1328. X        } while (isalpha(ch));
  1329. X    } else if (ch == CHAR_NULL) {    /* At end of line? */
  1330. X        curtoken = E_END;
  1331. X        return;
  1332. X    } else {                        /* Must be punctuation */
  1333. X        do {
  1334. X            *p++ = ch;
  1335. X            nextch();
  1336. X        } while (ch && !isalpha(ch) && !isdigit(ch) && ch != CHAR_SPACE
  1337. X                                    && ch != CHAR_QUOTES);
  1338. X    }
  1339. X    *p = CHAR_NULL;
  1340. X    ungetnext();
  1341. X
  1342. X    /* Check for character A - F */
  1343. X    if (curstring[1] == CHAR_NULL) {
  1344. X        switch (curstring[0]) {
  1345. X            case 'A': case 'B': case 'C':
  1346. X            case 'D': case 'E': case 'F':
  1347. X                curvalue = curstring[0] + 10 - 'A';
  1348. X                curtoken = E_NUMBER;
  1349. X                return;
  1350. X        }
  1351. X    }
  1352. X
  1353. X    /* Now find token that matches string */
  1354. X    for (i = 0; i < MAXINDEX; i++) {
  1355. X        if (!strcmp(curstring, indexes[i].name)) {
  1356. X            curtoken = indexes[i].tag;
  1357. X            return;
  1358. X        }
  1359. X    }
  1360. X    for (i = 0; tokens[i].name; i++) {
  1361. X        if (!strcmp(curstring, tokens[i].name)) {
  1362. X            curtoken = tokens[i].tag;
  1363. X            return;
  1364. X        }
  1365. X    }
  1366. X    scripterror("unrecognised symbol '");
  1367. X    print2(curstring,"' in expression\n");
  1368. X    Cleanup(10);
  1369. X}
  1370. X
  1371. X
  1372. X/*
  1373. X *        com_select()
  1374. X *        ------------
  1375. X *        This command parses the expression in the command buffer starting
  1376. X *        at position compos, and builds an expression tree representing it.
  1377. X *        This tree is stored in tree[], starting at element 0. This expression
  1378. X *        tree is used when match() is called.
  1379. X */
  1380. X
  1381. Xvoid com_select()
  1382. X{
  1383. X    treepos = 0;
  1384. X    readtoken();
  1385. X    bnf_expression(tree);
  1386. X}
  1387. X
  1388. X/*
  1389. X *        bnf_expression()
  1390. X *        ----------------
  1391. X *        Parses the BNF line:
  1392. X *
  1393. X *        Expression ::= Boolean | Boolean Operator Expression | ALL
  1394. X *
  1395. X */
  1396. Xvoid bnf_expression(e)
  1397. XEXPR *e;
  1398. X{
  1399. X    EXPR dummy;
  1400. X
  1401. X    if (curtoken == E_ALL)
  1402. X        e->field = E_ALL;
  1403. X    else {
  1404. X        bnf_boolean(&dummy);
  1405. X        if (curtoken == E_AND || curtoken == E_OR) {
  1406. X            e->field   = curtoken;
  1407. X            e->left    = newnode();
  1408. X            e->right   = newnode();
  1409. X            *(e->left) = dummy;
  1410. X            readtoken();
  1411. X            bnf_expression(e->right);
  1412. X        } else
  1413. X            *e = dummy;
  1414. X    }
  1415. X}
  1416. X
  1417. X/*
  1418. X *        bnf_boolean()
  1419. X *        -------------
  1420. X *        Parses the following BNF line:
  1421. X *
  1422. X *        Boolean    ::= NOT Boolean                |
  1423. X *                    '(' Expression ')'        |
  1424. X *                    BoolIdent                |
  1425. X *                    NumIdent    Op Value    |
  1426. X *                    StringIdent Op String    |
  1427. X *                    DateIdent    Op Date
  1428. X */
  1429. Xvoid bnf_boolean(e)
  1430. XEXPR *e;
  1431. X{
  1432. X    char *p;
  1433. X
  1434. X    e->field = curtoken;
  1435. X    switch (curtoken) {
  1436. X
  1437. X        case E_NOT:
  1438. X            e->left = newnode();
  1439. X            readtoken();
  1440. X            bnf_boolean(e->left);
  1441. X            break;
  1442. X
  1443. X        case E_OPENPAR:
  1444. X            readtoken();
  1445. X            bnf_expression(e);
  1446. X            if (curtoken != E_CLOSEPAR) {
  1447. X                scripterror("missing close parenthesis\n");
  1448. X                Cleanup(10);
  1449. X            }
  1450. X            readtoken();
  1451. X            break;
  1452. X
  1453. X        case I_BINARY:
  1454. X        case I_VALID:
  1455. X        case I_ONLINE:
  1456. X        case I_LOCAL:
  1457. X        case E_TEXT:
  1458. X        case E_INVALID:
  1459. X        case E_OFFLINE:
  1460. X        case E_REMOTE:
  1461. X            readtoken();
  1462. X            break;
  1463. X
  1464. X        case I_ACCESS:
  1465. X        case I_SECTION:
  1466. X        case I_DIRECTORY:
  1467. X        case I_DISKDIRNUM:
  1468. X        case I_SIZE:
  1469. X        case I_KSIZE:
  1470. X            readtoken();
  1471. X            bnf_op(e);
  1472. X            if (curtoken != E_NUMBER) {
  1473. X                scripterror("number expected in expression\n");
  1474. X                Cleanup(10);
  1475. X            }
  1476. X            e->num = curvalue;
  1477. X            readtoken();
  1478. X            break;
  1479. X
  1480. X        case I_COMMENT:
  1481. X        case I_DISKNAME:
  1482. X        case I_NAME:
  1483. X        case I_OWNER:
  1484. X        case I_PATHNAME:
  1485. X            readtoken();
  1486. X            bnf_op(e);
  1487. X            if (curtoken != E_STRING) {
  1488. X                scripterror("string expected in expression\n");
  1489. X                Cleanup(10);
  1490. X            }
  1491. X            e->text = mymalloc(strlen(curstring)+1);
  1492. X            strcpy(e->text, curstring);
  1493. X            /*
  1494. X             *        Now check the string, and see if it contains any wildcard
  1495. X             *         characters. If it does, use operation W_{string}
  1496. X             *        instead of E_{string}. If it doesn't, use the standard
  1497. X             *        strcmp which is much faster.
  1498. X             */
  1499. X            for (p = curstring; *p; *p++) {
  1500. X                if (*p == '*' || *p == '?') {
  1501. X                    e->field = tokentowild(e->field);
  1502. X                    break;
  1503. X                }
  1504. X            }
  1505. X            readtoken();
  1506. X            break;
  1507. X
  1508. X        case I_DATE:
  1509. X            readtoken();
  1510. X            bnf_op(e);
  1511. X            bnf_date(e);
  1512. X            break;
  1513. X
  1514. X        default:
  1515. X            scripterror("error in expression\n");
  1516. X            Cleanup(10);
  1517. X    }
  1518. X}
  1519. X
  1520. X/*
  1521. X *        bnf_op
  1522. X *        ------
  1523. X *        Sets the operation field of the specified expression to the value
  1524. X *        of the next token on the command line.
  1525. X */
  1526. Xvoid bnf_op(e)
  1527. XEXPR *e;
  1528. X{
  1529. X    switch (curtoken) {
  1530. X        case E_EQ:
  1531. X        case E_NE:
  1532. X        case E_LT:
  1533. X        case E_GT:
  1534. X        case E_LE:
  1535. X        case E_GE:
  1536. X            e->op = curtoken;
  1537. X            readtoken();
  1538. X            break;
  1539. X
  1540. X        default:
  1541. X            scripterror("expected comparison operator\n");
  1542. X            Cleanup(10);
  1543. X    }
  1544. X}
  1545. X
  1546. X/*
  1547. X *        bnf_date()
  1548. X *        -----------
  1549. X *        Reads a date from the command line, validates it, and sets the
  1550. X *        'num' field in the expression to its numerical value. The date
  1551. X *        is in the format "dd-mon-yy", e.g. "15-Jun-89"
  1552. X */
  1553. Xvoid bnf_date(e)
  1554. XEXPR *e;
  1555. X{
  1556. X    int day, month, year;
  1557. X
  1558. X    if (curtoken != E_STRING) {
  1559. X        scripterror("expected date string in expression\n");
  1560. X        Cleanup(10);
  1561. X    }
  1562. X
  1563. X    if (strlen(curstring) != 9 ||
  1564. X            curstring[2] != '-' || curstring[6] != '-') {
  1565. X        scripterror("Invalid date format (should be dd-mon-yy)\n");
  1566. X        Cleanup(10);
  1567. X    }
  1568. X
  1569. X    day = atoi(curstring);
  1570. X    year = atoi(curstring+7);
  1571. X    for (month = 0; month < 12 && strnicmp(curstring+3, months[month], 3);
  1572. X                                                        month++)
  1573. X        ;
  1574. X    if ((day < 1 || day > 31) || (month < 1 || month > 12) ||
  1575. X                (year < 1 || year > 99)) {
  1576. X        scripterror("Invalid date format (should be dd-mon-yy)\n");
  1577. X        Cleanup(10);
  1578. X    }
  1579. X    e->num = (((year * 13) + month) << 5) + day;
  1580. X    readtoken();
  1581. X}
  1582. END_OF_FILE
  1583. if test 11470 -ne `wc -c <'src/expression.c'`; then
  1584.     echo shar: \"'src/expression.c'\" unpacked with wrong size!
  1585. fi
  1586. # end of 'src/expression.c'
  1587. fi
  1588. if test -f 'src/makefile' -a "${1}" != "-c" ; then 
  1589.   echo shar: Will not clobber existing file \"'src/makefile'\"
  1590. else
  1591. echo shar: Extracting \"'src/makefile'\" \(1075 characters\)
  1592. sed "s/^X//" >'src/makefile' <<'END_OF_FILE'
  1593. X#
  1594. X# Lattice LKM makefile, for Lattice C V5.04
  1595. X#
  1596. X# BBSindex (C) Copyright Eddy Carroll, December 1989
  1597. X#
  1598. X
  1599. X
  1600. XCFLAGS    = -cus -ms -j88i #-D3
  1601. XOPT        = -O
  1602. X#BFLAGS    = sc sd map ram:map addsym
  1603. XBFLAGS    = sc sd map ram:map nd
  1604. XASM        = lc:asm
  1605. X#START    = lib:catch.o
  1606. XSTART    = tiny.o
  1607. X
  1608. X.c.o:
  1609. X    lc $(CFLAGS) $(OPT) -Hsystem.sym $*.c
  1610. X.a.o:
  1611. X    $(ASM) -isys:include/ -u $*.a
  1612. X.n.doc:
  1613. X    nro >$*.doc -ms:an $*.n
  1614. X.h.sym:
  1615. X    copy $*.h to ram:t/dummy.c 
  1616. X    lc $(CFLAGS) -ph -o$*.sym ram:t/dummy.c
  1617. X    delete ram:t/dummy.c
  1618. X
  1619. X#
  1620. X# Makefile dependencies
  1621. X#
  1622. XOBJS   = bbsindex.o checkfiles.o command.o expression.o format.o sort.o
  1623. X
  1624. Xall: bbsindex
  1625. X
  1626. Xbbsindex: $(OBJS) tiny.o
  1627. X    blink from $(START) $(OBJS) to bbsindex $(BFLAGS) lib lib:lc.lib
  1628. X
  1629. Xbbsindex.doc:    bbsindex.n
  1630. X
  1631. Xsystem.sym:        system.h
  1632. Xbbsindex.o:         bbsindex.c        system.sym  bbsindex.h  bbs.h
  1633. Xcheckfiles.o:    checkfiles.c    system.sym  bbsindex.h  bbs.h
  1634. Xcommand.o:        command.c        system.sym  bbsindex.h  bbs.h
  1635. Xexpression.o:    expression.c    system.sym  bbsindex.h  bbs.h
  1636. Xformat.o:        format.c        system.sym  bbsindex.h  bbs.h
  1637. Xsort.o:            sort.c            system.sym  bbsindex.h  bbs.h
  1638. Xtiny.o:            tiny.a
  1639. END_OF_FILE
  1640. if test 1075 -ne `wc -c <'src/makefile'`; then
  1641.     echo shar: \"'src/makefile'\" unpacked with wrong size!
  1642. fi
  1643. # end of 'src/makefile'
  1644. fi
  1645. if test -f 'src/sort.c' -a "${1}" != "-c" ; then 
  1646.   echo shar: Will not clobber existing file \"'src/sort.c'\"
  1647. else
  1648. echo shar: Extracting \"'src/sort.c'\" \(3552 characters\)
  1649. sed "s/^X//" >'src/sort.c' <<'END_OF_FILE'
  1650. X/*
  1651. X * SORT.C
  1652. X *
  1653. X * This module contains the sorting routines that read sorting order from
  1654. X * the command line, and sort the file database according to that order.
  1655. X *
  1656. X */
  1657. X
  1658. X#ifndef LATTICE_50
  1659. X#include "system.h"
  1660. X#endif
  1661. X
  1662. X#include "bbsindex.h"
  1663. X
  1664. X
  1665. X/*
  1666. X *        Arrays used to determine sorting order for SORT.
  1667. X */
  1668. X
  1669. Xint i_order[MAXINDEX+1];
  1670. Xint i_ascend[MAXINDEX+1];
  1671. X
  1672. X
  1673. X/*
  1674. X *        sortcmp()
  1675. X *        ---------
  1676. X *        This function is called by qsort. It compares the two specified
  1677. X *        elements, and returns -ve, 0 or +ve to indicate whether the second
  1678. X *        record is greater than, equal or less than the first, using the
  1679. X *        sorting criteria defined in SORT.
  1680. X */
  1681. X
  1682. X/*
  1683. X *        DOCMP is a macro which sets cmp equal to the value of the enclosed
  1684. X *        expression if i_ascend[i] is true, or the negative of the expression
  1685. X *        if i_ascend is false.
  1686. X */
  1687. X#define DOCMP(x)    (cmp = (i_ascend[i] ? (x) : -(x)))
  1688. Xint sortcmp(ptr1,ptr2)
  1689. XUDHEAD **ptr1, **ptr2;
  1690. X{
  1691. X    UDHEAD *p1 = *ptr1, *p2 = *ptr2;
  1692. X    int i, cmp = 0;
  1693. X
  1694. X    /*
  1695. X     *        Note safety exit - last element of i_order is guaranteed == I_ANY
  1696. X     */
  1697. X    for (i = 0; !cmp; i++) {
  1698. X        switch (i_order[i]) {
  1699. X
  1700. X            case I_ANY:            return(0);
  1701. X
  1702. X            case I_ACCESS:        DOCMP(p1->accesses - p2->accesses);
  1703. X                                break;
  1704. X            case I_BINARY:        DOCMP(p2->bin - p1->bin);
  1705. X                                break;
  1706. X            case I_COMMENT:        DOCMP(stricmp(p1->desc, p2->desc));
  1707. X                                break;
  1708. X            case I_DISKNAME:    DOCMP(stricmp(p1->disk_name, p2->disk_name));
  1709. X                                break;
  1710. X            case I_SECTION:        DOCMP(p1->section - p2->section);
  1711. X                                break;
  1712. X            case I_ONLINE:        DOCMP(p2->online - p1->online);
  1713. X                                break;
  1714. X            case I_LOCAL:        DOCMP(p2->local - p1->local);
  1715. X                                break;
  1716. X            case I_NAME:        DOCMP(strcmp(p1->cat_name, p2->cat_name));
  1717. X                                break;
  1718. X            case I_OWNER:        DOCMP(strcmp(p1->owner, p2->owner));
  1719. X                                break;
  1720. X            case I_PATHNAME:    DOCMP(strcmp(dirnames[p1->dirnum],
  1721. X                                             dirnames[p2->dirnum]));
  1722. X                                break;
  1723. X            case I_DIRECTORY:    DOCMP(p1->dir - p2->dir);
  1724. X                                break;
  1725. X            case I_DISKDIRNUM:    DOCMP(p1->dirnum - p2->dirnum);
  1726. X                                break;
  1727. X            case I_VALID:        DOCMP(p2->valid - p1->valid);
  1728. X                                break;
  1729. X            case I_DATE:        DOCMP(p1->date - p2->date);
  1730. X                                break;
  1731. X            case I_SIZE:        DOCMP(p1->length - p2->length);
  1732. X                                break;
  1733. X            case I_KSIZE:        DOCMP(BTOK(p1->length) - BTOK(p2->length));
  1734. X                                break;
  1735. X        }
  1736. X    }
  1737. X    return (cmp);
  1738. X}
  1739. X
  1740. X
  1741. X/*
  1742. X *        com_sort()
  1743. X *        ----------
  1744. X *        This command sorts the file database into order, according to
  1745. X *        the indexes specified. Each index may be optionally followed by
  1746. X *        a + or - to indirect sorting direction (ascending or descending).
  1747. X *        There must be no space between the direction and the +/-.
  1748. X */
  1749. Xvoid com_sort()
  1750. X{
  1751. X    char *index, *p;
  1752. X    int i, j;
  1753. X    int ascend;
  1754. X
  1755. X    CHECKDATABASE();
  1756. X
  1757. X    sorted = TRUE;
  1758. X    for (i = 0; i < MAXINDEX && compos < comlen; i++) {
  1759. X        index = getstring();
  1760. X        p = index + strlen(index) - 1;
  1761. X
  1762. X        /*
  1763. X         *        Now check to see if sorting direction specified, and adjust
  1764. X         *        string if it was. Set 'ascend' to TRUE if ascending,
  1765. X         *        else FALSE.
  1766. X         */
  1767. X        ascend = TRUE;
  1768. X        if (*p == CHAR_ASCEND || *p == CHAR_DESCEND) {
  1769. X            if (*p == CHAR_DESCEND)
  1770. X                ascend = FALSE;
  1771. X            *p = CHAR_NULL;
  1772. X        }
  1773. X
  1774. X        /*
  1775. X         *        Now match index, and setup appropriate entry in array
  1776. X         */
  1777. X
  1778. X        for (j = 0; j < MAXINDEX && strcmp(index,indexes[j].name); j++)
  1779. X            ;
  1780. X        if (j == MAXINDEX) {
  1781. X            scripterror("unknown index ");
  1782. X            print2(index, "\n");
  1783. X            Cleanup(10);
  1784. X        }
  1785. X        i_order[i]    = indexes[j].tag;
  1786. X        i_ascend[i]    = ascend;
  1787. X    }
  1788. X    if (i == 0) {
  1789. X        i_order[i] = I_NAME;
  1790. X        i_ascend[i++] = TRUE;
  1791. X    }
  1792. X    i_order[i] = I_ANY;
  1793. X
  1794. X    /* Finally, do the sort! */
  1795. X    qsort(ptrblock, numrecs, sizeof(UDHEAD *), sortcmp);
  1796. X}
  1797. END_OF_FILE
  1798. if test 3552 -ne `wc -c <'src/sort.c'`; then
  1799.     echo shar: \"'src/sort.c'\" unpacked with wrong size!
  1800. fi
  1801. # end of 'src/sort.c'
  1802. fi
  1803. if test -f 'src/system.h' -a "${1}" != "-c" ; then 
  1804.   echo shar: Will not clobber existing file \"'src/system.h'\"
  1805. else
  1806. echo shar: Extracting \"'src/system.h'\" \(191 characters\)
  1807. sed "s/^X//" >'src/system.h' <<'END_OF_FILE'
  1808. X/* Include files for BBSindex */
  1809. X
  1810. X#include <exec/types.h>
  1811. X#include <proto/dos.h>
  1812. X#include <proto/exec.h>
  1813. X#include <proto/intuition.h>
  1814. X#include <ctype.h>
  1815. X#include <string.h>
  1816. X#include <time.h>
  1817. END_OF_FILE
  1818. if test 191 -ne `wc -c <'src/system.h'`; then
  1819.     echo shar: \"'src/system.h'\" unpacked with wrong size!
  1820. fi
  1821. # end of 'src/system.h'
  1822. fi
  1823. if test -f 'src/tiny.a' -a "${1}" != "-c" ; then 
  1824.   echo shar: Will not clobber existing file \"'src/tiny.a'\"
  1825. else
  1826. echo shar: Extracting \"'src/tiny.a'\" \(6132 characters\)
  1827. sed "s/^X//" >'src/tiny.a' <<'END_OF_FILE'
  1828. X*:ts=8
  1829. X****************************************************************************
  1830. X*                                       *
  1831. X* TINY.A                  (C) Copyright Eddy Carroll 1989  *
  1832. X* ~~~~~~                  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~  *
  1833. X*                                       *
  1834. X* Replacement startup code for Lattice C V5.04. Use instead of c.o       *
  1835. X* This has many features stripped out to allow small utilities to have       *
  1836. X* as small a filesize as possible. In particular, don't call any of the    *
  1837. X* stdio functions.                               *
  1838. X*                                       *
  1839. X****************************************************************************
  1840. X
  1841. X    INCLUDE "exec/types.i"
  1842. X    INCLUDE "exec/alerts.i"
  1843. X    INCLUDE "exec/nodes.i"
  1844. X    INCLUDE "exec/lists.i"
  1845. X    INCLUDE "exec/ports.i"
  1846. X    INCLUDE "exec/libraries.i"
  1847. X    INCLUDE "exec/tasks.i"
  1848. X    INCLUDE "libraries/dos.i"
  1849. X    INCLUDE "libraries/dosextens.i"
  1850. X    INCLUDE "workbench/startup.i"
  1851. X    INCLUDE "exec/funcdef.i"
  1852. X    INCLUDE "exec/exec_lib.i"
  1853. X    INCLUDE "libraries/dos_lib.i"
  1854. X
  1855. XMAXARGS        EQU 100    ; Maximum number of command line arguments from CLI
  1856. XAbsExecBase EQU 4    ; Welcome to the only fixed point in the universe
  1857. X
  1858. X* A useful macro to let us call library routines
  1859. Xcallsys macro
  1860. X    CALLLIB _LVO\1
  1861. X    endm
  1862. X
  1863. X    xdef    XCEXIT
  1864. X    xdef    exit
  1865. X    xref    LinkerDB
  1866. X    xref    _BSSBAS
  1867. X    xref    _BSSLEN
  1868. X
  1869. X    csect    text,0,0,1,2        * xref's after this are 16-bit reloc
  1870. X    xref    main            * Name of C program to start with.
  1871. X
  1872. Xstart:
  1873. X    movem.l d1-d6/a0-a6,-(a7)
  1874. XREGSIZE EQU    (6+7)*4
  1875. X    lea    REGSIZE(a7),A5        * Determine old stack pointer
  1876. X    move.l    a0,a2            * Save command pointer
  1877. X    move.l    d0,d2            * and command length
  1878. X    lea    LinkerDB,a4        * Load base register
  1879. X
  1880. X    move.l    AbsExecBase.W,a6
  1881. X    move.l    a6,SysBase(A4)
  1882. X    move.l    a7,_StackPtr(A4)    * Save stack ptr
  1883. X
  1884. X    suba.l    a1,a1
  1885. X    callsys    FindTask        * Find out our task ID
  1886. X    move.l    d0,a3
  1887. X
  1888. X    move.l    a5,D0              * get top of stack
  1889. X    sub.l    4(a5),D0        * compute bottom
  1890. X    add.l    #128,D0         * allow for parms overflow
  1891. X    move.l    D0,_base(A4)        * save for stack checking
  1892. X
  1893. X    lea    DOSName(A4),A1
  1894. X    moveq.l    #0,D0
  1895. X    callsys    OpenLibrary
  1896. X    move.l    D0,DOSBase(A4)
  1897. X    bne    getcom
  1898. XnoDOS:
  1899. X    moveq.l #100,d0
  1900. X    bra    exit2
  1901. X
  1902. X*------ find command name:
  1903. Xgetcom:
  1904. X    move.l  pr_CLI(a3),a0
  1905. X    add.l    a0,a0
  1906. X    add.l    a0,a0
  1907. X    move.l    cli_CommandName(a0),a1
  1908. X    add.l    a1,a1
  1909. X    add.l    a1,a1
  1910. X
  1911. X*------ collect parameters:
  1912. X    move.l    d2,d0            * get command line length
  1913. X    moveq.l #0,d1
  1914. X    move.b    (a1)+,d1
  1915. X    move.l    a1,_ProgramName(A4)
  1916. X    add.l    d1,d0            * add length of command name
  1917. X    addq.l    #1,d0            * allow for space after command
  1918. X
  1919. X    clr.w    -(A7)            * set null terminator for command line
  1920. X    addq.l    #1,D0            * force to even number of bytes
  1921. X    andi.w    #$fffe,D0        * (round up)
  1922. X    sub.l    D0,A7            * make room on stack for command line
  1923. X    subq.l    #2,D0
  1924. X    clr.w    0(A7,D0)
  1925. X
  1926. X*------ copy command line onto stack
  1927. X    move.l    d2,d0            * get command line length
  1928. X    subq.l    #1,d0
  1929. X    add.l    d1,d2
  1930. X
  1931. Xcopy_line:
  1932. X    move.b    0(A2,D0.W),0(A7,D2.W)    * copy command line to stack
  1933. X    subq.l    #1,d2
  1934. X    dbf    d0,copy_line
  1935. X    move.b    #' ',0(a7,d2.w)     * add space between command and parms
  1936. X    subq.l    #1,d2
  1937. X
  1938. Xcopy_cmd:
  1939. X    move.b    0(a1,d2.w),0(a7,d2.w)    * copy command name to stack
  1940. X    dbf    d2,copy_cmd
  1941. X    move.l    a7,a1            * Get pointer to new command line
  1942. X
  1943. X    sub.l    #(MAXARGS*4),a7        * Reserve space for argv[]
  1944. X    move.l    a7,a2            * Initialise base into array
  1945. X    move.l    a2,a3            * Save base of argv
  1946. X    moveq    #0,d2            * Initialise argc
  1947. X
  1948. X*
  1949. X* From here on down, A1 is pointer into command line
  1950. X*
  1951. Xbuild_argv:
  1952. X    bsr.s    getnext            * Read next character from line
  1953. X    bcs.s    doquote            * If quote, handle
  1954. X    beq.s    build_argv        * If white space, skip over it
  1955. X
  1956. X    lea    -1(a1),a0        * Get address of this parameter
  1957. X    bsr.s    bumpargv        * Store it to argv[] array
  1958. Xbuild_2:
  1959. X    bsr.s    getnext            * Get next character
  1960. X    bne.s    build_2            * If not white space, keep looking
  1961. X    clr.b    -1(a1)            * Zero-terminate current argument
  1962. X    bra.s    build_argv        * And go back to get next argument
  1963. X
  1964. Xdoquote:
  1965. X    move.l    a1,a0            * Get pointer to this argument
  1966. X    bsr.s    bumpargv        * Output it to argv[]
  1967. Xquote_2:
  1968. X    bsr.s    getnext            * Get next character
  1969. X    bcc.s    quote_2            * If not quote, keep looking
  1970. X    clr.b    -1(a1)            * Zero-terminate current argument
  1971. Xquote_3:
  1972. X    bsr.s    getnext            * Get next character
  1973. X    bne.s    quote_3            * Skip until space reached
  1974. X    beq.s    build_argv        * Go back and read next argument
  1975. X
  1976. Xbumpargv:
  1977. X    move.l    a0,(a2)+        * Output ptr to current argument
  1978. X    addq    #1,d2            * Increment argc
  1979. X    cmpi    #MAXARGS,d2        * Used up all our arguments yet?
  1980. X    bls.s    qrts            * If not, then return
  1981. X    moveq    #110,d0            * Else set return code
  1982. X    bra.s    exit2            * And exit
  1983. X
  1984. X*
  1985. X* Reads next character from command line. If zero, never returns, but
  1986. X* drops into call to main. Else, returns, with C=1 if character is quote,
  1987. X* Z=1 if character is white space.
  1988. X*
  1989. Xgetnext:
  1990. X    move.b    (a1)+,d0        * Get character from command line
  1991. X    beq.s    get_2            * Exit if end of line
  1992. X    cmp.b    #34,d0            * Check if quote
  1993. X    beq.s    isquote            *
  1994. X    cmp.b    #32,d0            * Check if space
  1995. X    beq.s    isspace            *
  1996. X    cmp.b    #9,d0            * Or tab
  1997. X    beq.s    isspace            *
  1998. X    cmp.b    #10,d0            * Or end of line
  1999. Xisspace:
  2000. X    andi    #$1E,ccr        * Clear carry flag, retaining Z
  2001. Xqrts    rts
  2002. X
  2003. Xisquote:
  2004. X    ori    #1,ccr            * Set carry flag
  2005. X    andi    #$FB,ccr        * Clear zero flag
  2006. X    rts                * And return
  2007. X
  2008. Xget_2:
  2009. X    move.l    a3,-(a7)        * Push argv onto stack
  2010. X    move.l    d2,-(a7)        * Push argc onto stack
  2011. X
  2012. X    lea    _BSSBAS,a3        * get base of BSS
  2013. X    moveq    #0,d1
  2014. X    move.l    #_BSSLEN,d0        * get length of BSS in longwords
  2015. X    bra.s    clr_lp            * and clear for length given
  2016. Xclr_bss move.l    d1,(a3)+
  2017. Xclr_lp    dbf    d0,clr_bss
  2018. X
  2019. Xdomain:
  2020. X    jsr    main(PC)        * Call main(argc,argv)
  2021. X    moveq.l #0,d0            * Set successful status
  2022. X    bra.s    exit2
  2023. X
  2024. Xexit:
  2025. X_exit:
  2026. XXCEXIT:
  2027. X    move.l    4(SP),d0        * Extract return code
  2028. Xexit2:
  2029. X    move.l    d0,-(a7)
  2030. X    move.l    AbsExecBase.W,a6
  2031. X    move.l    DOSBase(A4),a1
  2032. X    callsys CloseLibrary        * Close Dos library
  2033. X
  2034. X*------ this rts sends us back to DOS:
  2035. XexitToDOS:
  2036. X    MOVE.L    (A7)+,D0
  2037. X    movea.l _StackPtr(a4),SP    * Restore stack ptr
  2038. X    movem.l (a7)+,d1-d6/a0-a6
  2039. X    rts
  2040. X
  2041. X*-----------------------------------------------------------------------
  2042. X* Global definitions
  2043. X*
  2044. X    csect    __MERGED,1,,2,2
  2045. X
  2046. X    xdef    NULL,SysBase,LoadAddress,DOSBase
  2047. X    xdef    _oserr,_OSERR,_ONBREAK
  2048. X    xdef    _ProgramName,_StackPtr,_base
  2049. X
  2050. XNULL           dc.l    0
  2051. X_base           dc.l    0
  2052. X_oserr           equ     *
  2053. X_OSERR           dc.l    0
  2054. X_ONBREAK       dc.l    0
  2055. XSysBase        dc.l    0
  2056. XLoadAddress    dc.l    0
  2057. X_StackPtr      dc.l    0
  2058. XDOSBase        dc.l    0
  2059. X_ProgramName   dc.l    0
  2060. XDOSName        dc.b    'dos.library',0
  2061. X
  2062. X    END
  2063. END_OF_FILE
  2064. if test 6132 -ne `wc -c <'src/tiny.a'`; then
  2065.     echo shar: \"'src/tiny.a'\" unpacked with wrong size!
  2066. fi
  2067. # end of 'src/tiny.a'
  2068. fi
  2069. echo shar: End of archive 1 \(of 3\).
  2070. cp /dev/null ark1isdone
  2071. MISSING=""
  2072. for I in 1 2 3 ; do
  2073.     if test ! -f ark${I}isdone ; then
  2074.     MISSING="${MISSING} ${I}"
  2075.     fi
  2076. done
  2077. if test "${MISSING}" = "" ; then
  2078.     echo You have unpacked all 3 archives.
  2079.     rm -f ark[1-9]isdone
  2080. else
  2081.     echo You still need to unpack the following archives:
  2082.     echo "        " ${MISSING}
  2083. fi
  2084. ##  End of shell archive.
  2085. exit 0
  2086. -- 
  2087. Submissions to comp.sources.amiga and comp.binaries.amiga should be sent to:
  2088.     amiga@cs.odu.edu    
  2089. or    amiga@xanth.cs.odu.edu    ( obsolescent mailers may need this address )
  2090. or    ...!uunet!xanth!amiga    ( very obsolescent mailers need this address )
  2091.  
  2092. Comments, questions, and suggestions s should be addressed to ``amiga-request''
  2093. (only use ``amiga'' for submissions) at the above addresses.
  2094.